package com.example.PolimiAssistant.utils;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.util.Log;

/**
 * AccountDataManager.java
 *
 * This class acts as the service provider for the android account information
 * for the android framework. Manages the controlled retrieval and modification
 * of the data in the android account manager framework.
 *
 */
public class AccountDataManager {

    /**
     * The tag used for log
     */
    private static final String TAG = AccountDataManager.class.getSimpleName();

    public static boolean createAccount(Context context, String username, String password,
                                        String oAuthToken){

        boolean answer = false;

        //1. Initiate the account manager
        AccountManager accountManager = AccountManager.get(context);

        //2. Create account
        Account newUserAccount;
        newUserAccount = new Account(username, AuthenticationConstants.ACCOUNT_TYPE);

        //3. Add the account
        try{

            //3.1 Encrypt the password
            String encryptedPassword = SecurityUtils.encryptToHex(password);

            //3.2 Add the account to the account manager
            accountManager.addAccountExplicitly(newUserAccount, encryptedPassword,null);

            //3.3 Add the token to the account
            accountManager.setAuthToken(newUserAccount,
                    AuthenticationConstants.PARAM_AUTHTOKEN_TYPE,oAuthToken);

            answer = true;

        }catch(Exception e){

            Log.i(TAG, e.getLocalizedMessage());
            answer = false;
        }

        return answer;
    }

    /**
     * Check if an account with the specific user name exists or not
     * @param context  The context used
     * @param username The user name of the account
     * @return If the account exists, return the account
     *         Otherwise return null
     */
    public static Account getUserAccount(Context context, String username) {

        android.accounts.AccountManager accountManager = android.accounts.AccountManager.get(context);
        Account[] accounts = accountManager.getAccountsByType(AuthenticationConstants.ACCOUNT_TYPE);

        for (Account account : accounts) {
            if (account.name.equalsIgnoreCase(username)) {
                return account;
            }
        }

        return null;
    }

    /**
     * This method deletes the account from the device.
     *
     * @param context
     * @param username
     * @return
     */
    public static void deleteAccount(Context context, String username){

        AccountManager accountManager;
        accountManager = AccountManager.get(context);

        //1. Get the users account
        Account account = getUserAccount(context, username);

        //2. Delete the account
        accountManager.removeAccount(account, null, null);

    }

    /**
     * Check if an account exists or not
     * @param context  The context used
     * @return If the account exists, return the account
     *         Otherwise return null
     */
    public static boolean isThereAnAccount(Context context) {

        //1. Get the accounts from the account manager
        android.accounts.AccountManager accountManager = android.accounts.AccountManager.get(context);
        Account[] accounts = accountManager.getAccountsByType(AuthenticationConstants.ACCOUNT_TYPE);

        //2. Check if the returned statement is null or have contents
        if(accounts != null){

            //Check if the returned account is unique

            //If one account
            if(accounts.length == 1){

                Log.d(TAG, "An account was found");
                return true;

            }else if(accounts.length == 0){

                //If 0 accounts where found
                Log.d(TAG, "No account was found");
                return false;

            }else{

                //If something weird happened
                Log.d(TAG, "Error: Less than 0 accounts or more than one account was found");
                return false;
            }

        }else{

            Log.d(TAG, "The getAccountsByType method returned NULL");
            return false;
        }

    }

    /**
     * Obtains the password stored in the account manager.
     * Password is encrypted, so it must be decrypted to get its real value
     * @param context  The context used
     * @param username The user name that the password is associated
     * @return The password stored in the account manager
     *         "" if the account is not set
     */
    public static String getPasswordyByUserName(Context context, String username) {

        android.accounts.AccountManager accountManager = android.accounts.AccountManager.get(context);
        String encryptedPassword;
        String decryptedPassword = "";

        Account account = getUserAccount(context, username);
        if (account != null) {

            encryptedPassword = accountManager.getPassword(account);
            try {
                decryptedPassword = SecurityUtils.decrypt(encryptedPassword);
            } catch (Exception e) {
                Log.e(TAG, e.getLocalizedMessage(), e);
            }
        }

        return decryptedPassword;
    }

    /**
     * Set the encrypted password in the user account. If the account doesn't exist
     * before, it creates a new one.
     * @param password The password to be stored in the account manager
     * @param username The user name associated with the password
     * @return true if the password has been set
     *         false otherwise
     */
    public static boolean setPasswordByUserName(Context context, String username, String password) {

        String accountType = AuthenticationConstants.ACCOUNT_TYPE;
        android.accounts.AccountManager accountManager = android.accounts.AccountManager.get(context);

        // Encrypt the password
        try {

            String encryptedPassword = SecurityUtils.encryptToHex(password);
            Account account = getUserAccount(context, username);

            if (account != null) {
                // Check if the old password is the same as the new one
                String oldPassword = accountManager.getPassword(account);
                if (!oldPassword.equalsIgnoreCase(encryptedPassword)) {
                    accountManager.setPassword(account, encryptedPassword);
                }
            }
            // If the account doesn't exist before, create it.
            else {
                Account newUserAccount = new Account(username, accountType);
                accountManager.addAccountExplicitly(newUserAccount, encryptedPassword, null);
            }
            return true;

        } catch (Exception e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return false;
        }
    }
}
